﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml;
using log4net;
using Sgml;
using Softyum.ForexAgent.Site;
using Softyum.Common.net;

namespace Softyum.ForexAgent.Controls
{
    public partial class NewsPage : UserControl
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(NewsPage));

        private NewsManager newsManager = new NewsManager();

        private WebPage webSite;
        public WebPage WebSite 
        {
            set
            {
                webSite = value;
                SetWebSite(value);
            }
            get
            {
                return webSite;
            }
        }
        
        public NewsPage()
        {
            //
            InitializeComponent();
        }

        private void SetWebSite(WebPage site)
        {
            //
            foreach (var item in site.Columns)
            {
                DataGridViewColumn col;
                if (!string.IsNullOrEmpty(item.Link))
                {
                    col = new DataGridViewLinkColumn();
                }
                else
                {
                    col = new DataGridViewTextBoxColumn();
                }
                col.Name = item.Name;
                col.HeaderText = item.Title;

                if (item.Width > 0)
                {
                    col.Width = item.Width;
                }
                else
                {
                    col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                }
                //
                col.Tag = item;
                //
                dataGridView1.Columns.Add(col);
            }

            // start worker
            worker.RunWorkerAsync();
        }

        private void NewsListPage_Load(object sender, EventArgs e)
        {

        }

        private void linkLabelOption_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {

        }

        #region Worker Events
        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (log.IsDebugEnabled)
                log.Debug(string.Format("Worker start: {0}", webSite.Name));
            try
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Loading " + webSite.Url);
                }
                WebRequest request = WebRequest.Create(webSite.Url);
                WebResponse response = request.GetResponse();
                if (string.IsNullOrEmpty(webSite.Encoding))
                {
                    // try get from response header
                    webSite.Encoding = response.TryGetCharset(Encoding.Default).HeaderName;
                }
                using (Stream stream = response.GetResponseStream())
                {
                    IList<GroupCollection> entries = ParseResponseStream(stream);
                    e.Result = entries;
                }

            }
            finally
            {
                if (log.IsDebugEnabled)
                    log.Debug(string.Format("Worker end: {0}", webSite.Name));
            }
        }

        private IList<GroupCollection> ParseResponseStream(Stream stream)
        {
            using (StreamReader streamReader = new StreamReader(stream, Encoding.GetEncoding(webSite.Encoding)))
            {
                string text = streamReader.ReadToEnd();
                return ParseBlocks(text);
            }
        }

        private IList<GroupCollection> ParseBlocks(string text)
        {
            using (SgmlReader reader = new SgmlReader())
            {
                reader.DocType = "HTML";
                reader.InputStream = new StringReader(text);
                reader.WhitespaceHandling = WhitespaceHandling.None;
                XmlDocument doc = new XmlDocument();
                doc.Load(reader);
                XmlNodeList items = doc.SelectNodes(webSite.BlockPattern);
                if (log.IsDebugEnabled)
                {
                    log.Debug("Load " + items.Count + " blocks");
                }
                IList<GroupCollection> entries = new List<GroupCollection>();
                foreach (XmlNode item in items)
                {
                    string blockText = item.InnerXml;
                    if (log.IsDebugEnabled)
                    {
                        log.DebugFormat("{0}", item.InnerXml);
                    }

                    Regex regexObj = new Regex(webSite.EntryPattern);
                    Match matchResult = regexObj.Match(blockText);
                    if (matchResult.Success)
                    {
                        entries.Add(matchResult.Groups);
                    }
                }

                return entries;
            }
        }

        private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                log.Error(e.Error);
            }
            else if (e.Result != null)
            {
                StringCollection newNews = new StringCollection();
                bool isFirstShow = dataGridView1.Rows.Count == 0;
                this.dataGridView1.Rows.Clear();
                foreach (var item in e.Result as IList<GroupCollection>)
                {
                    bool isPrimaryFound = false;
                    DataGridViewRow row = dataGridView1.Rows[dataGridView1.Rows.Add()];
                    
                    foreach (DataGridViewCell cell in row.Cells)
                    {
                        DataGridViewColumn col = cell.OwningColumn;
                        WebPage.Column column = col.Tag as WebPage.Column;
                        cell.Value = item[column.Name].Value;
                        // Primary
                        if (column.Primary)
                        {
                            if (isPrimaryFound)
                                throw new Exception("More than one primary cloumn exist of site: " + webSite.Name);

                            // found primary for the news
                            isPrimaryFound = true;
                            // if new?
                            if (newsManager.IsNew(item[column.Name].Value))
                            {
                                // manage the new news
                                newsManager.Add(item[column.Name].Value);
                                // for show later
                                newNews.Add(item[column.Name].Value);
                            }
                        }
                        // Link
                        if (!string.IsNullOrEmpty(column.Link))
                        {
                            cell.Tag = item[column.Link].Value;
                        }
                        // ToolTip
                        if (!string.IsNullOrEmpty(column.Tooltip))
                        {
                            cell.ToolTipText = item[column.Tooltip].Value;
                        }
                    }

                    if (!isPrimaryFound)
                        throw new Exception("No primary column found for " + webSite.Name);
                }

                // we skip show the popup window when it's first shown
                if (!isFirstShow)
                {
                    if (newNews.Count > 0)
                    {
                        StringBuilder sb = new StringBuilder();
                        foreach (var item in newNews)
                        {
                            sb.AppendFormat("- {0}\r\n", item);
                        }
                        // Notify found newer news
                        CustomMessages.SendNewNews(Program.MainForm.Handle, webSite.Name, sb.ToString());
                    }
                }
            }

            // start new timer to restart worker
            Timer timer = new Timer();
            timer.Interval = webSite.Intval;
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            // stop timer
            using (Timer timer = sender as Timer)
            {
                timer.Stop();
            }
            // restart worker
            worker.RunWorkerAsync();
        }
        #endregion

        #region DataGridView Events
        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView view = sender as DataGridView;
            DataGridViewCell cell = view.Rows[e.RowIndex].Cells[e.ColumnIndex];
            if (cell is DataGridViewLinkCell)
            {
                string url = cell.Tag as string;
                Browser.Open(url);
            }
        }
        #endregion
    }
}
